Merged from gtk-2-6:
authorFederico Mena Quintero <federico@ximian.com>
Fri, 10 Jun 2005 05:54:28 +0000 (05:54 +0000)
committerFederico Mena Quintero <federico@src.gnome.org>
Fri, 10 Jun 2005 05:54:28 +0000 (05:54 +0000)
2005-06-10  Federico Mena Quintero  <federico@ximian.com>

Merged from gtk-2-6:

Fixes #162358:

* gtk/gtkfilechooserdefault.c (update_chooser_entry): Don't return
immediately if we are in CREATE_FOLDER mode, so that we can fill
the entry with the newly-selected folder.
(gtk_file_chooser_default_set_property): Warn against turning on
multiple selection for CREATE_FOLDER mode, or about setting that
action while multiple selection is on.
(update_chooser_entry): Change the entry's contents as well if we
are in CREATE_FOLDER mode.  If nothing is selected, clear the
chooser entry.
(trap_activate_cb): Don't trap enter/space if modifiers are
pressed.  This lets one use Ctrl-space to toggle rows in multiple
selection mode.
(gtk_file_chooser_default_should_respond): Clean up the if-chain
mess of special cases by using an array to determine what to do.
Also, for the save-entry case in CREATE_FOLDER mode, actually fix
the bug where the file chooser would switch to an existing folder
rather than confirming with it, and create the folder ourselves.
(error_creating_folder_over_existing_file_dialog): New function.

* gtk/gtkfilechooserentry.c (check_completion_callback): Only
insert the common prefix if we are in an "open" mode.  Use a
helper function.
(append_common_prefix): New helper function; code moved over from
check_completion_callback().
(find_common_prefix): New helper function.
(gtk_file_chooser_entry_focus): Append the common prefix if the
user requests it explicitly.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
gtk/gtkfilechooserdefault.c
gtk/gtkfilechooserentry.c

index a69ffc2a7f4d93ebfdd64be3d3a96fea152a351a..ee73f1e880433ec035a3338cc74f502026f9741f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2005-06-10  Federico Mena Quintero  <federico@ximian.com>
+
+       Merged from gtk-2-6:
+
+       Fixes #162358:
+
+       * gtk/gtkfilechooserdefault.c (update_chooser_entry): Don't return
+       immediately if we are in CREATE_FOLDER mode, so that we can fill
+       the entry with the newly-selected folder.
+       (gtk_file_chooser_default_set_property): Warn against turning on
+       multiple selection for CREATE_FOLDER mode, or about setting that
+       action while multiple selection is on.
+       (update_chooser_entry): Change the entry's contents as well if we
+       are in CREATE_FOLDER mode.  If nothing is selected, clear the
+       chooser entry.
+       (trap_activate_cb): Don't trap enter/space if modifiers are
+       pressed.  This lets one use Ctrl-space to toggle rows in multiple
+       selection mode.
+       (gtk_file_chooser_default_should_respond): Clean up the if-chain
+       mess of special cases by using an array to determine what to do.
+       Also, for the save-entry case in CREATE_FOLDER mode, actually fix
+       the bug where the file chooser would switch to an existing folder
+       rather than confirming with it, and create the folder ourselves.
+       (error_creating_folder_over_existing_file_dialog): New function.
+
+       * gtk/gtkfilechooserentry.c (check_completion_callback): Only
+       insert the common prefix if we are in an "open" mode.  Use a
+       helper function.
+       (append_common_prefix): New helper function; code moved over from
+       check_completion_callback().
+       (find_common_prefix): New helper function.
+       (gtk_file_chooser_entry_focus): Append the common prefix if the
+       user requests it explicitly.
+
 2005-06-10  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_expand): 
index a69ffc2a7f4d93ebfdd64be3d3a96fea152a351a..ee73f1e880433ec035a3338cc74f502026f9741f 100644 (file)
@@ -1,3 +1,37 @@
+2005-06-10  Federico Mena Quintero  <federico@ximian.com>
+
+       Merged from gtk-2-6:
+
+       Fixes #162358:
+
+       * gtk/gtkfilechooserdefault.c (update_chooser_entry): Don't return
+       immediately if we are in CREATE_FOLDER mode, so that we can fill
+       the entry with the newly-selected folder.
+       (gtk_file_chooser_default_set_property): Warn against turning on
+       multiple selection for CREATE_FOLDER mode, or about setting that
+       action while multiple selection is on.
+       (update_chooser_entry): Change the entry's contents as well if we
+       are in CREATE_FOLDER mode.  If nothing is selected, clear the
+       chooser entry.
+       (trap_activate_cb): Don't trap enter/space if modifiers are
+       pressed.  This lets one use Ctrl-space to toggle rows in multiple
+       selection mode.
+       (gtk_file_chooser_default_should_respond): Clean up the if-chain
+       mess of special cases by using an array to determine what to do.
+       Also, for the save-entry case in CREATE_FOLDER mode, actually fix
+       the bug where the file chooser would switch to an existing folder
+       rather than confirming with it, and create the folder ourselves.
+       (error_creating_folder_over_existing_file_dialog): New function.
+
+       * gtk/gtkfilechooserentry.c (check_completion_callback): Only
+       insert the common prefix if we are in an "open" mode.  Use a
+       helper function.
+       (append_common_prefix): New helper function; code moved over from
+       check_completion_callback().
+       (find_common_prefix): New helper function.
+       (gtk_file_chooser_entry_focus): Append the common prefix if the
+       user requests it explicitly.
+
 2005-06-10  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_expand): 
index a69ffc2a7f4d93ebfdd64be3d3a96fea152a351a..ee73f1e880433ec035a3338cc74f502026f9741f 100644 (file)
@@ -1,3 +1,37 @@
+2005-06-10  Federico Mena Quintero  <federico@ximian.com>
+
+       Merged from gtk-2-6:
+
+       Fixes #162358:
+
+       * gtk/gtkfilechooserdefault.c (update_chooser_entry): Don't return
+       immediately if we are in CREATE_FOLDER mode, so that we can fill
+       the entry with the newly-selected folder.
+       (gtk_file_chooser_default_set_property): Warn against turning on
+       multiple selection for CREATE_FOLDER mode, or about setting that
+       action while multiple selection is on.
+       (update_chooser_entry): Change the entry's contents as well if we
+       are in CREATE_FOLDER mode.  If nothing is selected, clear the
+       chooser entry.
+       (trap_activate_cb): Don't trap enter/space if modifiers are
+       pressed.  This lets one use Ctrl-space to toggle rows in multiple
+       selection mode.
+       (gtk_file_chooser_default_should_respond): Clean up the if-chain
+       mess of special cases by using an array to determine what to do.
+       Also, for the save-entry case in CREATE_FOLDER mode, actually fix
+       the bug where the file chooser would switch to an existing folder
+       rather than confirming with it, and create the folder ourselves.
+       (error_creating_folder_over_existing_file_dialog): New function.
+
+       * gtk/gtkfilechooserentry.c (check_completion_callback): Only
+       insert the common prefix if we are in an "open" mode.  Use a
+       helper function.
+       (append_common_prefix): New helper function; code moved over from
+       check_completion_callback().
+       (find_common_prefix): New helper function.
+       (gtk_file_chooser_entry_focus): Append the common prefix if the
+       user requests it explicitly.
+
 2005-06-10  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_expand): 
index 25571eec22fbb115702c8545cba072dfde066548..4b0df6c1fa799b6e0ddca70be712ff5a9f583375 100644 (file)
@@ -951,6 +951,21 @@ error_creating_folder_dialog (GtkFileChooserDefault *impl,
                path, error);
 }
 
+/* Shows an error about not being able to create a folder because a file with
+ * the same name is already there.
+ */
+static void
+error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
+                                                const GtkFilePath     *path,
+                                                GError                *error)
+{
+  error_dialog (impl,
+               _("The folder could not be created, as a file with the same name "
+                 "already exists.  Try using a different name for the folder, "
+                 "or rename the file first."),
+               path, error);
+}
+
 /* Shows an error dialog about not being able to create a filename */
 static void
 error_building_filename_dialog (GtkFileChooserDefault *impl,
@@ -3209,11 +3224,14 @@ trap_activate_cb (GtkWidget   *widget,
                  gpointer     data)
 {
   GtkFileChooserDefault *impl;
+  int modifiers;
 
   impl = (GtkFileChooserDefault *) data;
+
+  modifiers = gtk_accelerator_get_default_mod_mask ();
   
   if (event->keyval == GDK_slash &&
-      ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+      ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
     {
       location_popup_handler (impl, "/");
       return TRUE;
@@ -3223,6 +3241,7 @@ trap_activate_cb (GtkWidget   *widget,
        || event->keyval == GDK_ISO_Enter
        || event->keyval == GDK_KP_Enter
        || event->keyval == GDK_space)
+      && ((event->state && modifiers) == 0)
       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
           impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
     {
@@ -4056,9 +4075,12 @@ gtk_file_chooser_default_set_property (GObject      *object,
          {
            gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
            
-           if (action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->select_multiple)
+           if ((action == GTK_FILE_CHOOSER_ACTION_SAVE || action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+               && impl->select_multiple)
              {
-               g_warning ("Multiple selection mode is not allowed in Save mode");
+               g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
+                          "this is not allowed in multiple selection mode.  Resetting the file chooser "
+                          "to single selection mode.");
                set_select_multiple (impl, FALSE, TRUE);
              }
            impl->action = action;
@@ -4096,9 +4118,12 @@ gtk_file_chooser_default_set_property (GObject      *object,
     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
       {
        gboolean select_multiple = g_value_get_boolean (value);
-       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && select_multiple)
+       if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+           && select_multiple)
          {
-           g_warning ("Multiple selection mode is not allowed in Save mode");
+           g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
+                      "not allowed in SAVE or CREATE_FOLDER modes.  Ignoring the change and "
+                      "leaving the file chooser in single selection mode.");
            return;
          }
 
@@ -4899,15 +4924,19 @@ update_chooser_entry (GtkFileChooserDefault *impl)
   const GtkFileInfo *info;
   GtkTreeIter iter;
   GtkTreeIter child_iter;
+  gboolean change_entry;
 
-  if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+  if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
     return;
 
   g_assert (!impl->select_multiple);
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
 
   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
-    return;
+    {
+      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), "");
+      return;
+    }
 
   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
                                                  &child_iter,
@@ -4915,7 +4944,12 @@ update_chooser_entry (GtkFileChooserDefault *impl)
 
   info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
 
-  if (!gtk_file_info_get_is_folder (info))
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+    change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
+  else
+    change_entry = TRUE;                                /* ... unless we are in CREATE_FOLDER mode */
+
+  if (change_entry)
     _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
                                           gtk_file_info_get_display_name (info));
 }
@@ -5644,41 +5678,75 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
 
   if (current_focus == impl->browse_files_tree_view)
     {
+      /* The following array encodes what we do based on the impl->action and the
+       * number of files selected.
+       */
+      typedef enum {
+       NOOP,                   /* Do nothing (don't respond) */
+       RESPOND,                /* Respond immediately */
+       RESPOND_OR_SWITCH,      /* Respond immediately if the selected item is a file; switch to it if it is a folder */
+       ALL_FILES,              /* Respond only if everything selected is a file */
+       ALL_FOLDERS,            /* Respond only if everything selected is a folder */
+       SAVE_ENTRY,             /* Go to the code for handling the save entry */
+       NOT_REACHED             /* Sanity check */
+      } ActionToTake;
+      static const ActionToTake what_to_do[4][3] = {
+       /*                                0 selected            1 selected              many selected */
+       /* ACTION_OPEN */               { NOOP,                 RESPOND_OR_SWITCH,      ALL_FILES   },
+       /* ACTION_SAVE */               { SAVE_ENTRY,           RESPOND_OR_SWITCH,      NOT_REACHED },
+       /* ACTION_SELECT_FOLDER */      { RESPOND,              ALL_FOLDERS,            ALL_FOLDERS },
+       /* ACTION_CREATE_FOLDER */      { SAVE_ENTRY,           ALL_FOLDERS,            NOT_REACHED }
+      };
+
       int num_selected;
       gboolean all_files, all_folders;
+      int k;
+      ActionToTake action;
 
     file_list:
 
+      g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+
       selection_check (impl, &num_selected, &all_files, &all_folders);
 
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+      if (num_selected > 2)
+       k = 2;
+      else
+       k = num_selected;
+
+      action = what_to_do [impl->action] [k];
+
+      switch (action)
        {
-         if (num_selected != 1)         
-           return TRUE; /* zero means current folder; more than one means use the whole selection */    
-         else if (current_focus != impl->browse_files_tree_view)        
+       case NOOP:
+         return FALSE;
+
+       case RESPOND:
+         return TRUE;
+
+       case RESPOND_OR_SWITCH:
+         g_assert (num_selected == 1);
+
+         if (all_folders)
            {
-             /* a single folder is selected and a button was clicked */
-             switch_to_selected_folder (impl);          
-             return TRUE;
+             switch_to_selected_folder (impl);
+             return FALSE;
            }
-       }
-
-      if (num_selected == 0)
-       {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-             || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-           goto save_entry; /* it makes sense to use the typed name */
          else
-           return FALSE;
-       }
+           return TRUE;
 
-      if (num_selected == 1 && all_folders)
-       {
-         switch_to_selected_folder (impl);
-         return FALSE;
+       case ALL_FILES:
+         return all_files;
+
+       case ALL_FOLDERS:
+         return all_folders;
+
+       case SAVE_ENTRY:
+         goto save_entry;
+
+       default:
+         g_assert_not_reached ();
        }
-      else
-       return all_files;
     }
   else if (current_focus == impl->save_file_name_entry)
     {
@@ -5686,7 +5754,8 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       gboolean is_valid, is_empty;
       gboolean is_folder;
       gboolean retval;
-      GtkFileChooserEntry *entry;  
+      GtkFileChooserEntry *entry;
+      GError *error;
 
     save_entry:
 
@@ -5696,32 +5765,67 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
       path = check_save_entry (impl, &is_valid, &is_empty);
 
-      if (!is_empty && !is_valid)
+      if (!is_valid)
        return FALSE;
 
-      if (is_empty)
-       path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
-      
-      is_folder = check_is_folder (impl->file_system, path, NULL);
+      g_assert (!is_empty);
+
+      error = NULL;
+      is_folder = check_is_folder (impl->file_system, path, &error);
       if (is_folder)
        {
-         _gtk_file_chooser_entry_set_file_part (entry, "");
-         change_folder_and_display_error (impl, path);
-         retval = FALSE;
+         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+           {
+             _gtk_file_chooser_entry_set_file_part (entry, "");
+             change_folder_and_display_error (impl, path);
+             retval = FALSE;
+           }
+         else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+           {
+             retval = TRUE;
+           }
        }
       else
        {
-         /* check that everything up to the last component exists */
-         gtk_file_path_free (path);
-         path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
-         is_folder = check_is_folder (impl->file_system, path, NULL);
-         if (!is_folder)
+         if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+             && g_error_matches (error, GTK_FILE_SYSTEM_ERROR, GTK_FILE_SYSTEM_ERROR_NOT_FOLDER))
            {
-             change_folder_and_display_error (impl, path);
+             /* Oops, the user typed the name of an existing path which is not a folder */
+             error_creating_folder_over_existing_file_dialog (impl, path, error);
              retval = FALSE;
            }
          else
-           retval = TRUE;
+           {
+             GtkFilePath *parent_path;
+
+             /* check that everything up to the last component exists */
+
+             parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+             is_folder = check_is_folder (impl->file_system, parent_path, NULL);
+             if (!is_folder)
+               {
+                 change_folder_and_display_error (impl, parent_path);
+                 retval = FALSE;
+               }
+             else
+               {
+                 GError *create_error;
+
+                 create_error = NULL;
+                 if (gtk_file_system_create_folder (impl->file_system, path, &create_error))
+                   retval = TRUE;
+                 else
+                   {
+                     error_creating_folder_dialog (impl, path, create_error);
+                     retval = FALSE;
+                   }
+               }
+
+             gtk_file_path_free (parent_path);
+           }
+
+         if (error != NULL)
+           g_error_free (error);
        }
 
       gtk_file_path_free (path);
index 97b0f2327f9a83b920614abaad25a7dceef9dc33..4967832b90c9f82345db470d212c63621616436b 100644 (file)
@@ -384,28 +384,25 @@ maybe_append_separator_to_path (GtkFileChooserEntry *chooser_entry,
   return display_name;
 }
 
-static gboolean
-check_completion_callback (GtkFileChooserEntry *chooser_entry)
+/* Determines if the completion model has entries with a common prefix relative
+ * to the current contents of the entry.  Also, if there's one and only one such
+ * path, stores it in unique_path_ret.
+ */
+static void
+find_common_prefix (GtkFileChooserEntry *chooser_entry,
+                   gchar               **common_prefix_ret,
+                   GtkFilePath         **unique_path_ret)
 {
   GtkTreeIter iter;
-  gchar *common_prefix = NULL;
-  GtkFilePath *unique_path = NULL;
   gboolean valid;
 
-  GDK_THREADS_ENTER ();
-
-  g_assert (chooser_entry->file_part);
-
-  chooser_entry->check_completion_idle = NULL;
-
-  if (strcmp (chooser_entry->file_part, "") == 0)
-    goto done;
+  *common_prefix_ret = NULL;
+  *unique_path_ret = NULL;
 
   if (chooser_entry->completion_store == NULL)
-    goto done;
+    return;
 
-  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser_entry->completion_store),
-                                        &iter);
+  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (chooser_entry->completion_store), &iter);
 
   while (valid)
     {
@@ -420,14 +417,14 @@ check_completion_callback (GtkFileChooserEntry *chooser_entry)
 
       if (g_str_has_prefix (display_name, chooser_entry->file_part))
        {
-         if (!common_prefix)
+         if (!*common_prefix_ret)
            {
-             common_prefix = g_strdup (display_name);
-             unique_path = gtk_file_path_copy (path);
+             *common_prefix_ret = g_strdup (display_name);
+             *unique_path_ret = gtk_file_path_copy (path);
            }
          else
            {
-             gchar *p = common_prefix;
+             gchar *p = *common_prefix_ret;
              const gchar *q = display_name;
                  
              while (*p && *p == *q)
@@ -438,16 +435,26 @@ check_completion_callback (GtkFileChooserEntry *chooser_entry)
                  
              *p = '\0';
 
-             gtk_file_path_free (unique_path);
-             unique_path = NULL;
+             gtk_file_path_free (*unique_path_ret);
+             *unique_path_ret = NULL;
            }
        }
 
       g_free (display_name);
       gtk_file_path_free (path);
-      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser_entry->completion_store),
-                                       &iter);
+      valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (chooser_entry->completion_store), &iter);
     }
+}
+
+/* Finds a common prefix based on the contents of the entry and mandatorily appends it */
+static void
+append_common_prefix (GtkFileChooserEntry *chooser_entry,
+                     gboolean             highlight)
+{
+  gchar *common_prefix;
+  GtkFilePath *unique_path;
+
+  find_common_prefix (chooser_entry, &common_prefix, &unique_path);
 
   if (unique_path)
     {
@@ -457,19 +464,6 @@ check_completion_callback (GtkFileChooserEntry *chooser_entry)
       gtk_file_path_free (unique_path);
     }
 
-  switch (chooser_entry->action)
-    {
-    case GTK_FILE_CHOOSER_ACTION_SAVE:
-    case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
-      if (common_prefix && !g_str_has_suffix (common_prefix, "/"))
-       {
-         g_free (common_prefix);
-         common_prefix = NULL;
-       }
-      break;
-    default: ;
-    }
-
   if (common_prefix)
     {
       gint file_part_len;
@@ -489,16 +483,40 @@ check_completion_callback (GtkFileChooserEntry *chooser_entry)
          gtk_editable_insert_text (GTK_EDITABLE (chooser_entry),
                                    common_prefix, -1, 
                                    &pos);
-         gtk_editable_select_region (GTK_EDITABLE (chooser_entry),
-                                     chooser_entry->file_part_pos + file_part_len,
-                                     chooser_entry->file_part_pos + common_prefix_len);
          chooser_entry->in_change = FALSE;
 
-         chooser_entry->has_completion = TRUE;
+         if (highlight)
+           {
+             gtk_editable_select_region (GTK_EDITABLE (chooser_entry),
+                                         chooser_entry->file_part_pos + file_part_len,
+                                         chooser_entry->file_part_pos + common_prefix_len);
+             chooser_entry->has_completion = TRUE;
+           }
        }
-         
+
       g_free (common_prefix);
     }
+}
+
+static gboolean
+check_completion_callback (GtkFileChooserEntry *chooser_entry)
+{
+  GDK_THREADS_ENTER ();
+
+  g_assert (chooser_entry->file_part);
+
+  chooser_entry->check_completion_idle = NULL;
+
+  if (strcmp (chooser_entry->file_part, "") == 0)
+    goto done;
+
+  /* We only insert the common prefix without requiring the user to hit Tab in
+   * the "open" modes.  For "save" modes, the user must hit Tab to cause the prefix
+   * to be inserted.  That happens in gtk_file_chooser_entry_focus().
+   */
+  if (chooser_entry->action == GTK_FILE_CHOOSER_ACTION_OPEN
+      || chooser_entry->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    append_common_prefix (chooser_entry, TRUE);
 
  done:
 
@@ -660,13 +678,21 @@ static gboolean
 gtk_file_chooser_entry_focus (GtkWidget        *widget,
                              GtkDirectionType  direction)
 {
-  GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (widget);
+  GtkFileChooserEntry *chooser_entry;
+  GtkEditable *editable;
+  GtkEntry *entry;
   GdkModifierType state;
-  gboolean control_pressed = FALSE;
+  gboolean control_pressed;
+
+  chooser_entry = GTK_FILE_CHOOSER_ENTRY (widget);
+  editable = GTK_EDITABLE (widget);
+  entry = GTK_ENTRY (widget);
 
   if (!chooser_entry->eat_tabs)
     return GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
 
+  control_pressed = FALSE;
+
   if (gtk_get_current_event_state (&state))
     {
       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
@@ -681,13 +707,16 @@ gtk_file_chooser_entry_focus (GtkWidget        *widget,
     {
       gint pos = 0;
 
-      if (chooser_entry->has_completion)
-       gtk_editable_set_position (GTK_EDITABLE (widget),
-                                  GTK_ENTRY (widget)->text_length);
+      if (!chooser_entry->has_completion
+         && gtk_editable_get_position (editable) == entry->text_length)
+       append_common_prefix (chooser_entry, FALSE);
+
+      gtk_editable_set_position (editable, entry->text_length);
+
       /* Trigger the completion window to pop up again by a 
        * zero-length insertion, a bit of a hack.
        */
-      gtk_editable_insert_text (GTK_EDITABLE (widget), "", -1, &pos);
+      gtk_editable_insert_text (editable, "", -1, &pos);
 
       return TRUE;
     }